package org.jflame.web.spring.jackson;

import org.jflame.commons.util.StringHelper;

import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.servlet.mvc.method.annotation.AbstractMappingJacksonResponseBodyAdvice;

@Order(10)
public class JacksonDynamicFilterResponseBodyAdvice extends AbstractMappingJacksonResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return super.supports(returnType, converterType) && (returnType.hasMethodAnnotation(JacksonFilters.class)
                || returnType.hasMethodAnnotation(JacksonFilter.class));
    }

    @Override
    protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,
            MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
        if (returnType.hasMethodAnnotation(JacksonFilters.class)) {
            JacksonDynamicFilter jdfilter = new JacksonDynamicFilter();
            JacksonFilters filterProps = returnType.getMethodAnnotation(JacksonFilters.class);
            for (JacksonFilter jf : filterProps.value()) {
                addFitlerMap(jdfilter, jf);
            }
            bodyContainer.setFilters(jdfilter);
        } else if (returnType.hasMethodAnnotation(JacksonFilter.class)) {
            JacksonDynamicFilter jdfilter = new JacksonDynamicFilter();
            JacksonFilter filterProp = returnType.getMethodAnnotation(JacksonFilter.class);
            addFitlerMap(jdfilter, filterProp);
            bodyContainer.setFilters(jdfilter);
        }
    }

    void addFitlerMap(JacksonDynamicFilter jdfilter, JacksonFilter filterProp) {
        if (StringHelper.isNotEmpty(filterProp.include())) {
            jdfilter.include(filterProp.type(), split(filterProp.include()));
        } else {
            if (StringHelper.isNotEmpty(filterProp.exclude())) {
                jdfilter.exclude(filterProp.type(), split(filterProp.exclude()));
            }
        }
    }

    String[] split(String props) {
        return StringHelper.split(props.trim());
    }
}
